package site.teamo.biu.net.client.core.http_https_proxy.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import site.teamo.biu.net.client.configuration.ClientConfiguration;
import site.teamo.biu.net.client.core.http_https_proxy.ConnectionHandler;
import site.teamo.biu.net.common.constant.Protocol;
import site.teamo.biu.net.common.handler.ExceptionHandler;
import site.teamo.biu.net.common.util.HostPort;
import site.teamo.biu.net.common.util.HttpUtils;
import site.teamo.biu.net.common.web.mapper.SystemConfigMapper;
import site.teamo.biu.tool.spring.util.SpringApplicationContextHolder;

import java.util.concurrent.TimeUnit;

/**
 * @author haocongshun
 * @date 2023/06/08 16:33:14
 */
@Slf4j
public class BrowserRequestListeningServer {

    private final NioEventLoopGroup bossGroup;

    private final NioEventLoopGroup workerGroup;

    private final ConnectionHandler handler;

    public BrowserRequestListeningServer(ConnectionHandler handler) {
        this.bossGroup = new NioEventLoopGroup();
        this.workerGroup = new NioEventLoopGroup();
        this.handler = handler;
        ServerBootstrap bootstrap = new ServerBootstrap();
        int port = getPort();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new Initializer())
                .bind(port);
        log.info("http&https代理服务监听在:{}端口", port);
    }

    public void close() {
        this.bossGroup.shutdownGracefully();
        this.workerGroup.shutdownGracefully();
    }

    private int getPort() {
        SystemConfigMapper systemConfigMapper = SpringApplicationContextHolder.getBean(SystemConfigMapper.class);
        return Integer.parseInt(ClientConfiguration.HTTP_HTTPS_PROXY_SERVICE_LISTEN_PORT.getContent(systemConfigMapper));
    }

    private class Initializer extends ChannelInitializer<SocketChannel> {

        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline()
                    .addLast("idle", new IdleStateHandler(0, 0, 90, TimeUnit.SECONDS))
                    .addLast("http-decoder", new HttpRequestDecoder())
                    .addLast("http-encoder", new HttpResponseEncoder())
                    .addLast("browser-request-listening", new Handler())
                    .addLast("exception", new ExceptionHandler());
        }
    }

    private class Handler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (msg instanceof HttpRequest request) {
                ctx.channel().pipeline().remove(this);
                HostPort hostPort = HttpUtils.getHostPort(request);
                ctx.channel().config().setAutoRead(false);
                //如果是https的处理办法
                if (request.method() == HttpMethod.CONNECT) {
                    handler.https(hostPort.setProtocol(Protocol.HTTPS), ctx.channel());
                } else {
                    handler.http(hostPort.setProtocol(Protocol.HTTP), ctx.channel(), request);
                }
            } else {
                ctx.fireChannelRead(msg);
            }
        }
    }

}
